home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech's Sprocket™ / Sprocket (original from 1994) / Sprocket / Lib / DialogUtils.cp < prev    next >
Encoding:
Text File  |  1994-12-13  |  10.5 KB  |  409 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        DialogUtils.cp
  3.  
  4.     Contains:    Auto-sized error alert mechanism,
  5.                 ModalFilterProcs which correctly handle events,
  6.                 and Standard “Close Document” dialogs. 
  7.  
  8.     Written by: Dave Falkenburg
  9.  
  10.     Copyright:    © 1993-94 by Dave Falkenburg, all rights reserved.
  11.  
  12.     Change History (most recent first):
  13.      
  14.          <6>    11/23/94    DRF        Add ToggleCheckBox, a nice little dialog item utility.
  15.          <5>    11/16/94    DRF        Added explicit #include <SegLoad.h> for latest universal
  16.                                     headers. Also added cast to keep MPW CFront happier.
  17.          <4>    11/16/94    DRF        Add StdFilterProc for THINK C.
  18.          <3>     9/27/94    DRF         AppLib.h is now Sprocket.h
  19.          <2>      9/9/94    DRF        Reordered headers and removed redundant #includes.
  20.  */
  21.  
  22. #include "Sprocket.h"
  23.  
  24. #include <Fonts.h>
  25. #include <Resources.h>
  26. #include <TextUtils.h>
  27. #include <Threads.h>        //    For YieldToAnyThread()
  28. #include <StandardFile.h>    //    For ModalFilterYDProcPtr
  29. #include <SegLoad.h>        //    For ExitToShell()
  30.  
  31. //    Some types which should probably be defined in <Dialogs.h>
  32. //    NOTE: These must be aligned on 2-byte boundaries
  33. #if defined(powerc) || defined (__powerc)
  34. #pragma options align=mac68k
  35. #endif
  36.  
  37. struct DialogItem
  38.     {
  39.     long    usedByDialogManager;
  40.     Rect    boundsRect;
  41.     char    type;
  42.     char    length;
  43.     };
  44.  
  45. struct DialogItemList            //    a.k.a. a 'DITL'
  46.     {
  47.     short        count;
  48.     DialogItem    firstItem[1];
  49.     };
  50.  
  51. //    Restore default alignment
  52. #if defined(powerc) || defined(__powerc)
  53. #pragma options align=reset
  54. #endif
  55.  
  56. typedef    DialogItem        *DialogItemPtr;
  57. typedef    DialogItemList    **DialogItemListHandle;
  58. typedef    DialogTemplate    **DialogTemplateHandle;
  59.  
  60. #ifndef    powerc
  61. #ifdef    __SC__
  62.  
  63. extern pascal OSErr GetStdFilterProc(ModalFilterUPP *theProc)
  64.  THREEWORDINLINE(0x303C, 0x0203, 0xAA68);
  65.  
  66. pascal Boolean
  67. StdFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  68.     {
  69.     ModalFilterUPP    filterUPP;
  70.     OSErr            myErr;
  71.     Boolean            returnVal = false;
  72.     
  73.     //    Dialogs.h
  74.     
  75.     myErr = GetStdFilterProc(&filterUPP);
  76.     if (!myErr) returnVal = CallModalFilterProc(filterUPP,theDialog,anEvent,itemHit);
  77.     
  78.     return    returnVal;
  79.     }
  80.  
  81. #endif
  82. #endif
  83.  
  84. //    private function Prototypes
  85.  
  86. static    pascal Boolean    StandardDialogFilterProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  87. static    pascal Boolean    StandardDialogFilterYDProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit, void * yourData);
  88. static    pascal Boolean    StandardCloseDialogFilterProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  89. static    Boolean            FilterProcCommon(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  90.  
  91.  
  92.  
  93. ///////////////////////////////////////////////////////////
  94. //
  95. //    StandardAlert
  96. //
  97. //    An alternative to Alert() which uses the extended
  98. //    Dialog Manager capabilities.
  99. //
  100. //    I’m not sure we really need this call, but it seems
  101. //    to do the trick just fine.
  102.  
  103. short
  104. StandardAlert(    short dlogID,
  105.                 short defaultItem,                /* = ok */
  106.                 short cancelItem,                /* = 0 */
  107.                 ModalFilterUPP customFilterProc    /* = nil */)
  108.     {
  109.     DialogPtr        theDialog;
  110.     short            itemHit = 0;
  111.     ModalFilterUPP    filterToUse;
  112.     
  113.     HiliteWindowsForModalDialog(false);
  114.  
  115.     theDialog = GetNewDialog(dlogID,nil,(WindowPtr) -1);
  116.     if (defaultItem)
  117.         SetDialogDefaultItem(theDialog,defaultItem);
  118.     if (cancelItem)
  119.         SetDialogCancelItem(theDialog,cancelItem);
  120.  
  121.     if (customFilterProc)
  122.         filterToUse = customFilterProc;
  123.     else
  124.         filterToUse = StandardDialogFilter;
  125.  
  126.     do
  127.         ModalDialog(filterToUse,&itemHit);
  128.     while (itemHit == 0);
  129.     
  130.     DisposeDialog(theDialog);
  131.  
  132.     HiliteWindowsForModalDialog(true);
  133.  
  134.     return itemHit;
  135.     }
  136.  
  137.  
  138. ///////////////////////////////////////////////////////////
  139. //
  140. //    ErrorAlert
  141. //
  142. //    A nice error reporting routine which presents an
  143. //    auto-sized alert box containing the supplied text.
  144. //
  145. //    NOTE:    This routine ASSUMES the following 'DITL'
  146. //            structure:
  147. //
  148. //            item #1 : an “OK” button
  149. //            item #2 : a static text item, somewhere above #1
  150. //
  151. //    NOTE:    We probably need to worry more about low
  152. //            memory conditions-- this can probably
  153. //            be handled by a custom GrowZoneProc and
  154. //            reserve memory area large enough to hold
  155. //            all the space we’d need.
  156. //
  157.  
  158. void
  159. ErrorAlert(short stringList,short whichString)
  160.     {
  161.     Str255                    errorString;
  162.     GrafPtr                    oldPort,windowMgrPort;
  163.     short                    oldFont;
  164.     DialogTemplateHandle    errorDialogTemplate;
  165.     DialogItemListHandle    errorDialogItems;
  166.     TEHandle                aTEHandle;
  167.     Rect                    textRect;
  168.     short                    textHeight;
  169.     short                    additionalSpaceNeeded;
  170.     DialogItemPtr            okButtonItem,errorTextItem;
  171.     const StringPtr            nullStr = (StringPtr) "\p";
  172.  
  173.     GetIndString(errorString,stringList,whichString);
  174.     
  175.     errorDialogTemplate = (DialogTemplateHandle) Get1Resource('DLOG',kErrorAlertID);
  176.     HLock((Handle) errorDialogTemplate);
  177.     
  178.     errorDialogItems = (DialogItemListHandle) Get1Resource('DITL',(**errorDialogTemplate).itemsID);
  179.     HLock((Handle) errorDialogItems);
  180.     
  181.     //    Find the dialog items
  182.     
  183.     okButtonItem = (**errorDialogItems).firstItem;
  184.     errorTextItem = (DialogItemPtr) ((Ptr) okButtonItem + sizeof(DialogItem) + okButtonItem->length);
  185.     
  186.     GetPort(&oldPort);
  187.     GetWMgrPort(&windowMgrPort);
  188.     SetPort(windowMgrPort);
  189.     oldFont = qd.thePort->txFont;
  190.     TextFont(systemFont);
  191.  
  192.     aTEHandle = TENew(&textRect,&textRect);
  193.     TESetText(&errorString[1],errorString[0],aTEHandle);
  194.     textHeight = (*aTEHandle)->lineHeight * (*aTEHandle)->nLines;
  195.     TEDispose(aTEHandle);
  196.  
  197.     additionalSpaceNeeded = textHeight - (errorTextItem->boundsRect.bottom
  198.                             - errorTextItem->boundsRect.top);
  199.  
  200.     if (additionalSpaceNeeded > 0)
  201.         {
  202.         (**errorDialogTemplate).boundsRect.bottom += additionalSpaceNeeded;
  203.         errorTextItem->boundsRect.bottom += additionalSpaceNeeded;
  204.         OffsetRect(&okButtonItem->boundsRect,0,additionalSpaceNeeded);
  205.         }
  206.         
  207.     TextFont(oldFont);
  208.     SetPort(oldPort);
  209.     
  210.     InitCursor();
  211.     ParamText(errorString,nullStr,nullStr,nullStr);
  212.  
  213.     (void) StandardAlert(kErrorAlertID);
  214.  
  215.     ReleaseResource((Handle) errorDialogTemplate);
  216.     ReleaseResource((Handle) errorDialogItems);
  217.     }
  218.  
  219.  
  220. ///////////////////////////////////////////////////////////
  221. //
  222. //    FatalErrorAlert
  223. //
  224. //    A companion to ErrorAlert which also kills the process.
  225. //
  226.  
  227. void
  228. FatalErrorAlert(short stringList,short whichString)
  229.     {
  230.     ErrorAlert(stringList,whichString);
  231.     ExitToShell();
  232.     }
  233.  
  234.  
  235. ///////////////////////////////////////////////////////////
  236. //
  237. //    StandardDialogFilter and StandardDialogFilterYD
  238. //
  239. //    These function takes care of routing events not meant
  240. //    for the dialog window to other parts of the application.
  241. //
  242. //    Use them as an alternative to passing a NIL ModalFilterProc
  243. //    to ModalDialog() and CustomGet(Put)File. Unlike the default
  244. //    filter, these routines properly processes update events
  245. //    to keep background processes running.
  246. //
  247. //    The Thread Manager, if present, is also called to yield
  248. //    control to other cooperative threads within the process.
  249. //
  250. //    Because of pascal calling conventions we need two separate
  251. //    routines, but this is minimized by sharing implementation
  252. //    in FilterProcCommon.
  253. //
  254.  
  255. ModalFilterUPP    StandardDialogFilter
  256. = NewModalFilterProc(StandardDialogFilterProc);
  257.  
  258. ModalFilterYDUPP    StandardDialogFilterYD
  259. = NewModalFilterYDProc(StandardDialogFilterYDProc);
  260.  
  261. ModalFilterUPP    StandardCloseDialogFilter
  262. = NewModalFilterProc(StandardCloseDialogFilterProc);
  263.  
  264.  
  265. pascal Boolean
  266. StandardDialogFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  267.     {
  268.     //    Call through common code to check for events we’d like to handle.
  269.     //    If that is unsuccessful, call through the System 7 StdFilterProc
  270.     //    to handle CR, “CMD-.” & ESC in an international-friendly manner.
  271.  
  272.     if (FilterProcCommon(theDialog, anEvent, itemHit))
  273.         return true;
  274.     else
  275.         return (StdFilterProc(theDialog, anEvent, itemHit));
  276.     }
  277.  
  278.  
  279. pascal Boolean
  280. StandardDialogFilterYDProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit, void * /*unusedData*/)
  281.     {
  282.     //    We don’t call through to StdFilterProc since the
  283.     //    Standard File Package already does everything we need.
  284.  
  285.     return FilterProcCommon(theDialog, anEvent, itemHit);
  286.     }
  287.  
  288. void
  289. PseudoClickInDialogItem(DialogPtr theDialog, short itemToClick)
  290.     {
  291.     Handle    itemHandle;
  292.     Rect    itemBox;
  293.     long    finalTicks;
  294.     short    itemType;
  295.     
  296.     GetDialogItem(theDialog,itemToClick,&itemType,&itemHandle,&itemBox);
  297.  
  298.     HiliteControl((ControlHandle) itemHandle,inButton);
  299.     Delay(8,&finalTicks);
  300.     HiliteControl((ControlHandle) itemHandle,0);
  301.     }
  302.  
  303.  
  304. Boolean
  305. ToggleCheckBox(DialogPtr theDialog, short theCheckBox)
  306.     {
  307.     ControlHandle    itemHandle;
  308.     Rect            itemBox;
  309.     short            itemType;
  310.     
  311.     GetDialogItem(theDialog,theCheckBox,&itemType,(Handle *) &itemHandle,&itemBox);
  312.  
  313.     if (GetControlValue(itemHandle) == 1)
  314.         {
  315.         SetControlValue(itemHandle,0);
  316.         return false;
  317.         }
  318.     else
  319.         {
  320.         SetControlValue(itemHandle,1);
  321.         return true;
  322.         }
  323.     }
  324.  
  325.  
  326. pascal Boolean
  327. StandardCloseDialogFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  328.     {
  329.     if ((anEvent->what == keyDown))
  330.         {
  331.         char    c = (char) anEvent->message & charCodeMask;
  332.         
  333.         if ((c == 'd') || (c == 'D'))                //    NOT INTERNATIONAL FRIENDLY!!!
  334.             {
  335.             *itemHit = kDontSaveDocument;
  336.             PseudoClickInDialogItem(theDialog,kDontSaveDocument);
  337.             return true;
  338.             }
  339.         }
  340.  
  341.     //    Return through the common code above so that default item processing can happen
  342.     return StandardDialogFilterProc(theDialog, anEvent, itemHit);
  343.     }
  344.  
  345.  
  346. Boolean
  347. FilterProcCommon(DialogPtr theDialog, EventRecord * anEvent, short * /* itemHit */)
  348.     {
  349.     switch (anEvent->what)
  350.         {
  351.         case updateEvt:
  352.         case activateEvt:
  353.             //     Update or activate for the dialog window?
  354.             if (theDialog == (DialogPtr) anEvent->message)
  355.                 break;
  356.  
  357.             //    no, fall through to HandleEvent            
  358.             
  359.         case diskEvt:
  360.             HandleEvent(anEvent);
  361.             return(false);
  362.  
  363.         default:
  364.             break;        
  365.         }
  366.  
  367.     if (gHasThreadManager)        //    If we have threads, let them run!
  368.         YieldToAnyThread();
  369.  
  370.     return false;                //    We didn’t handle the event
  371.     }
  372.  
  373.  
  374. //////////////////////////////////////////////////////////////////
  375. //
  376. //    StandardCloseDocument
  377. //
  378. //    Provides the standard human interface for closing a document
  379. //
  380. //    NOTE: When we make TDocument class, this will become a method
  381. //          and probably won’t need any parameters.
  382. //
  383. //    NOTE:    StandardCloseResult matches the dialog items for 
  384.  
  385. StandardCloseResult
  386. StandardCloseDocument(const StringPtr documentType, StringPtr documentName,
  387.                       Boolean hasNewEditions, Boolean quitting)
  388.     {
  389.     short        whichAlert;
  390.     short        whichString;
  391.     StringPtr    nullStr = (StringPtr) "\p";
  392.     Str255        reasonForClosingStr;
  393.  
  394.     if (hasNewEditions)
  395.         whichAlert = kStandardCloseWithNewPubsAlertID;
  396.     else
  397.         whichAlert = kStandardCloseAlertID;
  398.     
  399.     if (quitting)
  400.         whichString = kQuittingStr;
  401.     else
  402.         whichString = kClosingStr;
  403.  
  404.     GetIndString(reasonForClosingStr,kStandardCloseStrings,whichString);
  405.     ParamText(documentType,documentName,reasonForClosingStr,nullStr);
  406.     
  407.     return ((StandardCloseResult) StandardAlert(whichAlert,kSaveDocument,kCancelSaveDocument,StandardCloseDialogFilter));
  408.     }
  409.